#!/usr/bin/env python
# -*- coding: utf-8 -*-

from twisted.internet import reactor
from twisted.internet import task
import stock_trade_pb2
import ot_pb2
import base_pb2
import trade_db_model_pb2
import random
import SocketTools
import time

gOrderList = dict()
gTradeList = dict()
gPosition = dict()

gMatchNoAndOrderNo = {
    u'MtoO': dict(),
    u'OtoM': dict()
}

gOrderCurrent = 0
gTradeCurrent = 0

gPubFlag = [False, False, False, False]

def pack(msg, send, type):
    body = send.SerializeToString()
    head = list(msg['head'])
    head[2] = type
    head[0] = len(body)
    return head, body

def get_OrderNo():
    global gOrderCurrent
    ret = gOrderCurrent
    gOrderCurrent += 1
    return str(ret)

def get_TradeNo():
    global gTradeCurrent
    ret = gTradeCurrent
    gTradeCurrent += 1
    return str(ret)

def add_OrderTrade(msg, protocol):

    global gTradeList
    global gOrderList
    global gPosition
    global gMatchNoAndOrderNo

    order_no = get_OrderNo()
    print '成交了:', order_no
    trade = trade_db_model_pb2.StockKnock()
    trade.fund_id = protocol.get_fund_id()
    trade.bs_flag = msg.bs_flag
    trade.order_no = order_no
    trade.market = msg.market
    trade.stock_id = msg.code
    trade.inner_match_no = get_TradeNo()
    trade.match_no = trade.inner_match_no
    trade.match_time = int(time.clock()*10000)
    trade.match_price = msg.price
    trade.match_volume = msg.qty
    trade.match_amount = msg.price * msg.qty
    trade.order_bs_flag = msg.bs_flag
    trade.order_volume = msg.qty
    trade.order_price = msg.price
    trade.recv_time = trade.match_time
    trade.data_date = trade.match_time
    trade.create_time = trade.match_time
    trade.total_knock_volume = msg.qty
    gTradeList[trade.order_no] = trade

    order = trade_db_model_pb2.StockOrder()
    order.id = order_no
    order.fund_id = protocol.get_fund_id()
    order.market = msg.market
    order.bs_flag = msg.bs_flag
    order.order_no = order_no
    order.stock_id = msg.code
    order.price = msg.price
    order.volume = msg.qty
    order.state = 6
    order.create_time = int(time.clock()*10000)
    gOrderList[order_no] = order

    if msg.bs_flag == 1:
        if gPosition.get(trade.stock_id, None) is None:
            gPosition[trade.stock_id] = trade_db_model_pb2.StockPosition()
        posi = gPosition[trade.stock_id]
        posi.volume += msg.qty
        posi.market_value += trade.match_amount
        posi.stock_id = trade.stock_id
        posi.market = msg.market
        posi.fund_id = protocol.get_fund_id()
        posi.create_time = int(time.clock()*10000)
        gPosition[trade.stock_id] = posi

        price = trade.match_amount / 10000.0
        protocol.set_freeze(protocol.get_freeze()+price)
        protocol.set_market_value(protocol.get_market_value()+price)
        protocol.set_money(protocol.get_money()-price)
    else:
        if gPosition.get(trade.stock_id, None) is None:
            return order_no
        posi = gPosition[trade.stock_id]
        posi.volume -= msg.qty
        if posi.volume < 0:
            posi.volume = 0
        gPosition[trade.stock_id] = posi

        price = msg.price * msg.qty / 10000.0
        protocol.set_freeze(protocol.get_freeze()+price)
        protocol.set_market_value(protocol.get_market_value()+price)
        protocol.set_money(protocol.get_money()-price)

    return order_no

def add_OrderList(msg, protocol, state):
    global gOrderList

    order_no = get_OrderNo()
    order = trade_db_model_pb2.StockOrder()
    order.id = order_no
    order.fund_id = protocol.get_fund_id()
    order.market = msg.market
    order.bs_flag = msg.bs_flag
    order.order_no = order_no
    order.stock_id = msg.code
    order.price = msg.price
    order.volume = msg.qty
    order.state = state
    order.create_time = int(time.clock()*10000)

    gOrderList[order_no] = order

    price = msg.price * msg.qty / 10000.0
    protocol.set_freeze(protocol.get_freeze()+price)
    protocol.set_market_value(protocol.get_market_value()+price)
    protocol.set_money(protocol.get_money()-price)

    return order_no

def sub_OrderList(msg, protocol):
    global gOrderList
    global gMatchNoAndOrderNo

    order = gOrderList.get(msg.order_no, None)
    if order is None:
        print 'sub_OrderList： None'
        return None
    order = gOrderList[msg.order_no]
    order.state = 5

    if order.bs_flag == 1:
        price = order.price * order.volume / 10000.0
        protocol.set_freeze(protocol.get_freeze()-price)
        protocol.set_market_value(protocol.get_market_value()-price)
        protocol.set_money(protocol.get_money()+price)

    return msg.order_no



def Handle_Asset(message, protocol):
    send = stock_trade_pb2.QueryAssetResponse()
    send.ret_code = 0
    send.stock_asset.fund_id = protocol.get_fund_id()
    send.stock_asset.asset = int(10000*(protocol.get_freeze() + protocol.get_money()))
    send.stock_asset.capital_balance = int(10000*(protocol.get_money() + protocol.get_freeze()))
    send.stock_asset.capital_avaliable = int(10000*(protocol.get_money()))
    send.stock_asset.capital_freezed_by_buy = int(10000*(protocol.get_freeze()))
    send.stock_asset.capital_freezed_by_others = 0
    send.stock_asset.market_value = int(10000*(protocol.get_market_value()))
    send.stock_asset.create_time = int(time.clock()*10000)
    return pack(message, send, base_pb2.CMD_QUERY_ASSET_RESP)

def position_operator(target, source):
    target.volume = source.volume
    target.market_value = source.market_value
    target.stock_id = source.stock_id
    target.market = source.market
    target.fund_id = source.fund_id
    target.create_time = source.create_time

def Handle_Position(message, protocol):
    global gPosition
    recv = stock_trade_pb2.QueryPositionRequest()
    recv.ParseFromString(message['body'])
    send = stock_trade_pb2.QueryPositionResponse()
    if recv.code != "":
        posi = gPosition.get(recv.code, None)
        if posi:
            send.ret_code = 0
            addItem = send.stock_position.add()
            position_operator(addItem, posi)
        else:
            send.ret_code = -1
            send.ret_message = 'code is miss!'

    else:
        send.ret_code = 0
        for key in gPosition:
            posi = gPosition[key]
            addItem = send.stock_position.add()
            position_operator(addItem, posi)
    return pack(message, send, base_pb2.CMD_QUERY_STOCK_POSITION_RESP)

def order_operator(target, source):
    target.id = source.id
    target.fund_id = source.fund_id
    target.market = source.market
    target.bs_flag = source.bs_flag
    target.order_no = source.order_no
    target.stock_id = source.stock_id
    target.price = source.price
    target.volume = source.volume
    target.state = source.state
    target.create_time = source.create_time

def Handle_Order(message, protocol):
    global gOrderList
    recv = stock_trade_pb2.QueryOrderRequest()
    recv.ParseFromString(message['body'])
    send = stock_trade_pb2.QueryStockOrderResponse()
    if recv.order_no != "":
        order = gOrderList.get(recv.order_no, None)
        if order:
            send.ret_code = 0
            addItem = send.stock_order.add()
            order_operator(addItem, order)
        else:
            send.ret_code = -1
            send.ret_message = 'code is miss!'
    else:
        send.ret_code = 0
        for key in gOrderList:
            order = gOrderList[key]
            addItem = send.stock_order.add()
            order_operator(addItem, order)
    return pack(message, send, base_pb2.CMD_QUERY_STOCK_ORDER_RESP)

def trade_operator(target, source):
    target.fund_id = source.fund_id
    target.bs_flag = source.bs_flag
    target.order_no = source.order_no
    target.market = source.market
    target.stock_id = source.stock_id
    target.inner_match_no = source.inner_match_no
    target.match_no = source.match_no
    target.match_time = source.match_time
    target.match_price = source.match_price
    target.match_volume = source.match_volume
    target.match_amount = source.match_amount
    target.order_bs_flag = source.order_bs_flag
    target.order_volume = source.order_volume
    target.order_price = source.order_price
    target.recv_time = source.recv_time
    target.data_date = source.data_date
    target.create_time = source.create_time
    target.total_knock_volume = source.total_knock_volume

def Handle_Knock(message, protocol):
    global gTradeList
    recv = stock_trade_pb2.QueryStockKnockRequest()
    recv.ParseFromString(message['body'])
    send = stock_trade_pb2.QueryStockKnockResponse()
    if recv.order_no != "":
        trade = gTradeList.get(recv.order_no, None)
        if trade:
            send.ret_code = 0
            addItem = send.stock_knock.add()
            trade_operator(addItem, trade)
        else:
            send.ret_code = -1
            send.ret_message = 'code is miss!'
    else:
        send.ret_code = 0
        for key in gTradeList:
            trade = gTradeList[key]
            addItem = send.stock_knock.add()
            trade_operator(addItem, trade)
    return pack(message, send, base_pb2.CMD_QUERY_STOCK_KNOCK_RESP)

def Handle_Subscribe(message, protocol):
    recv = stock_trade_pb2.SubTradeMsgRequest()
    recv.ParseFromString(message['body'])

    global gPubFlag
    if recv.type == 0x0001:
        gPubFlag[0] = True
    elif recv.type == 0x0002:
        gPubFlag[1] = True
    elif recv.type == 0x0004:
        gPubFlag[2] = True
    elif recv.type == 0x0008:
        gPubFlag[3] = True

    send = stock_trade_pb2.SubTradeMsgResponse()
    send.ret_code = 0
    return pack(message, send, base_pb2.CMD_SUBSCRIBE_TRADE_RESP)

import SocketTools

gReqID = 0

def PUB(protocol, no, code):
    tools = SocketTools.StructProtocol()
    global gReqID
    gReqID += 1

    send = trade_db_model_pb2.StockAsset()
    send.fund_id = protocol.get_fund_id()
    send.asset = int(10000*(protocol.get_freeze() + protocol.get_money()))
    send.capital_balance = int(10000*(protocol.get_money() + protocol.get_freeze()))
    send.capital_avaliable = int(10000*(protocol.get_money()))
    send.capital_freezed_by_buy = int(10000*(protocol.get_freeze()))
    send.capital_freezed_by_others = 0
    send.market_value = int(10000*(protocol.get_market_value()))
    send.create_time = int(time.clock()*10000)
    send = send.SerializeToString()

    protoList = protocol.get_proto_list()
    for proto in protoList:
        proto.transport.write(tools.pack([len(send), 0x0010, base_pb2.CMD_SUB_ASSET_REQ, str(gReqID)], send))

    global gTradeList
    if code and gTradeList.get(no, None) is not None:
        trade = gTradeList[no]
        send = stock_trade_pb2.QueryStockKnockResponse()
        send.ret_code = 0
        item = send.stock_knock.add()
        trade_operator(item, trade)
        send = send.SerializeToString()

        protoList = protocol.get_proto_list()
        for proto in protoList:
            proto.transport.write(tools.pack([len(send), 0x0010, base_pb2.CMD_SUB_STOCK_KNOCK_REQ, str(gReqID)], send))

    global gOrderList
    if no and gOrderList.get(no, None) is not None:
        order = gOrderList[no]
        send = stock_trade_pb2.QueryStockOrderResponse()
        send.ret_code = 0
        item = send.stock_order.add()
        order_operator(item, order)
        send = send.SerializeToString()

        protoList = protocol.get_proto_list()
        for proto in protoList:
            proto.transport.write(tools.pack([len(send), 0x0010, base_pb2.CMD_SUB_STOCK_ORDER_REQ, str(gReqID)], send))

    global gPosition
    if code and gPosition.get(code, None) is not None:
        posi = gPosition[code]
        send = stock_trade_pb2.QueryPositionResponse()
        send.ret_code = 0
        item = send.stock_position.add()
        position_operator(item, posi)
        send = send.SerializeToString()

        protoList = protocol.get_proto_list()
        for proto in protoList:
            proto.transport.write(tools.pack([len(send), 0x0010, base_pb2.CMD_SUB_STOCK_POSITION_REQ, str(gReqID)], send))

def Handle_SingleOrder(message, protocol):
    recv = stock_trade_pb2.SingleOrderReq()
    recv.ParseFromString(message['body'])
    # if recv.policy_id == 'trade':
    if int(time.clock()*100) % 2:
        order_no = add_OrderTrade(recv, protocol)
        ret_message = 'This Order is Trade!'
    else:
        order_no = add_OrderList(recv, protocol, 1)
        ret_message = 'This Order Wating Cancel!'
    send = stock_trade_pb2.SingleOrderResp()
    send.ret_code = 0
    send.order_no = order_no
    send.ret_message = ret_message

    PUB(protocol, order_no, recv.code)

    return pack(message, send, base_pb2.CMD_SINGLE_ORDER_RESP)

def Handle_SingleWithdrawal(message, protocol):
    recv = stock_trade_pb2.SingleCancelReq()
    recv.ParseFromString(message['body'])

    ret = sub_OrderList(recv, protocol)

    PUB(protocol, recv.order_no, '')

    send = stock_trade_pb2.SingleOrderResp()
    send.ret_code = 0 if ret != None else -1
    send.order_no = recv.order_no
    send.ret_message = 'Cancel success!' if ret != None else "Cancel Failed!"

    return pack(message, send, base_pb2.CMD_SINGLE_ORDER_RESP)

SWITCH = {
    base_pb2.CMD_SINGLE_ORDER_REQ: Handle_SingleOrder,
    base_pb2.CMD_SINGLE_WITHDRAWAL_REQ: Handle_SingleWithdrawal,
    base_pb2.CMD_QUERY_ASSET_REQ: Handle_Asset,
    base_pb2.CMD_QUERY_STOCK_POSITION_REQ: Handle_Position,
    base_pb2.CMD_QUERY_STOCK_ORDER_REQ: Handle_Order,
    base_pb2.CMD_QUERY_STOCK_KNOCK_REQ: Handle_Knock,
    base_pb2.CMD_SUBSCRIBE_TRADE_REQ: Handle_Subscribe
}

def Handle(message, protocol):
    return SWITCH[message['head'][2]](message, protocol)

